package org.springblade.modules.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.admin.dto.plan.PlanContentExcelSearchDTO;
import org.springblade.modules.admin.entity.MaintainPlanContent;
import org.springblade.modules.admin.entity.MaintainSign;
import org.springblade.modules.admin.entity.UserSignDetail;
import org.springblade.modules.admin.enums.TaskStatusEnum;
import org.springblade.modules.admin.mapper.PlanContentExcelMapper;
import org.springblade.modules.admin.service.IMaintainSignService;
import org.springblade.modules.admin.service.PlanContentExcelService;
import org.springblade.modules.admin.service.UserSignDetailService;
import org.springblade.modules.admin.vo.plan.ExcelPlanContentVo;
import org.springblade.modules.admin.vo.plan.PerformanceVoV2;
import org.springblade.modules.admin.vo.plan.PlanUserVo;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zcc
 * @version 1.0
 * @date 2021/10/22 8:56
 */
@Slf4j
@Service
public class PlanContentExcelServiceImpl extends BaseServiceImpl<PlanContentExcelMapper, MaintainPlanContent> implements PlanContentExcelService {

	@Resource
	private IMaintainSignService maintainSignService;

	@Resource
	private UserSignDetailService userSignDetailService;

	@Override
	public List<PerformanceVoV2> getPerformance(PlanContentExcelSearchDTO planContentExcelSearchDTO, IPage<PlanUserVo> page) {

		List<PerformanceVoV2> resultList = new ArrayList<>(100);
		//获取所有人员
		List<PlanUserVo> planUserVoInfo = baseMapper.getPlanUserVoInfo(page, planContentExcelSearchDTO.getUserName(), planContentExcelSearchDTO.getUserStatus(), AuthUtil.getTenantId());
		List<Long> userIds = planUserVoInfo.stream().map(PlanUserVo::getUserId).collect(Collectors.toList());
		planContentExcelSearchDTO.setUserIds(userIds);
		Map<Long, List<PlanUserVo>> usersMap = planUserVoInfo.stream().collect(Collectors.groupingBy(PlanUserVo::getUserId));

		//获取维保任务
		List<ExcelPlanContentVo> planList = baseMapper.getPlanContentInfo(planContentExcelSearchDTO);
		Map<Long, List<ExcelPlanContentVo>> plansMap = planList.stream().collect(Collectors.groupingBy(ExcelPlanContentVo::getUserId));
		Map<Long, List<ExcelPlanContentVo>> plansMap2 = planList.stream().collect(Collectors.groupingBy(ExcelPlanContentVo::getPlanId));
		List<Long> planIds = planList.stream().map(ExcelPlanContentVo::getPlanId).distinct().collect(Collectors.toList());

		//签到信息
		List<MaintainSign> signList = new ArrayList<>();
		Map<Long, List<MaintainSign>> signMap = new HashMap<>();
		if(Func.isNotEmpty(planIds)){
			signList = maintainSignService.list(Wrappers.<MaintainSign>lambdaQuery().in(MaintainSign::getPlanId, planIds));
			if(Func.isNotEmpty(signList)){
				signList.stream().collect(Collectors.groupingBy(MaintainSign::getUserId));
			}
		}

		//用户考勤信息
		List<UserSignDetail> signDetailList = userSignDetailService.getList(planContentExcelSearchDTO);
		Map<Long, List<UserSignDetail>> userSignDetailMap = signDetailList.stream().filter(o -> o.getUserId() != null).collect(Collectors.groupingBy(UserSignDetail::getUserId));


		//数据处理
		for (Long userId : userIds) {

			PlanUserVo planUserVo = usersMap.get(userId).get(0);
			List<ExcelPlanContentVo> excelPlanContentVos = plansMap.get(userId);
			PerformanceVoV2 performanceVoV2 = new PerformanceVoV2();
			BeanUtil.copyProperties(planUserVo, performanceVoV2);
			if (excelPlanContentVos != null) {
				List<Long> elevatorIds = excelPlanContentVos.stream().map(ExcelPlanContentVo::getElevatorId).collect(Collectors.toList());
				performanceVoV2.setMaintainElevatorCount(elevatorIds.stream().distinct().collect(Collectors.toList()).size());

				List<Long> finishElevatorIds = excelPlanContentVos.stream().filter(o -> o.getPlanStatus() == TaskStatusEnum.BY_SIGN.getStatus()).map(ExcelPlanContentVo::getElevatorId).collect(Collectors.toList());
				performanceVoV2.setFinishElevatorCount(finishElevatorIds.stream().distinct().collect(Collectors.toList()).size());
				performanceVoV2.setPlanWorkload(elevatorIds.size());


				BigDecimal finishWorkload = performanceVoV2.getFinishWorkload();
				BigDecimal inTimeWorkload1 = performanceVoV2.getInTimeWorkload();
				for (ExcelPlanContentVo excelPlanContentVo : excelPlanContentVos) {
					List<ExcelPlanContentVo> excelPlanContentVos1 = plansMap2.get(excelPlanContentVo.getPlanId());
					int counts = 0;
					int counts1 = 0;
					for (ExcelPlanContentVo excelPlanContentVo1 : excelPlanContentVos1) {
						if (excelPlanContentVo1.getSignUser() != null && excelPlanContentVo1.getSignUser().getIsTakePartIn() && excelPlanContentVo1.getPlanStatus() == TaskStatusEnum.BY_SIGN.getStatus()) {
							counts = counts + 1;
						}

						if (excelPlanContentVo.getPlanEndTime() != null) {
							String format = DateUtil.format(excelPlanContentVo.getPlanDate(), "yyyy-MM-dd");
							String format1 = DateUtil.format(excelPlanContentVo.getPlanEndTime(), "yyyy-MM-dd");
							if (excelPlanContentVo1.getSignUser() != null && excelPlanContentVo1.getSignUser().getIsTakePartIn() && excelPlanContentVo1.getPlanStatus() == TaskStatusEnum.BY_SIGN.getStatus() && format.equals(format1)) {
								counts1 = counts1 + 1;
							}
						}

					}
					if (counts > 0) {
						BigDecimal divide = Convert.toBigDecimal(1).divide(Convert.toBigDecimal(counts), 2, BigDecimal.ROUND_HALF_UP);
						finishWorkload = finishWorkload.add(divide);
					}
					if (counts1 > 0) {
						BigDecimal divide = Convert.toBigDecimal(1).divide(Convert.toBigDecimal(counts1), 2, BigDecimal.ROUND_HALF_UP);
						inTimeWorkload1 = inTimeWorkload1.add(divide);
					}
				}
				performanceVoV2.setFinishWorkload(finishWorkload);
				performanceVoV2.setInTimeWorkload(inTimeWorkload1);
				if (Convert.toDouble(performanceVoV2.getFinishWorkload()) > 0) {
					BigDecimal inTimeWorkloadRatio = performanceVoV2.getInTimeWorkload().divide(performanceVoV2.getFinishWorkload(), 2, BigDecimal.ROUND_HALF_UP);
					performanceVoV2.setInTimeWorkloadRatio(inTimeWorkloadRatio);
				}
				performanceVoV2.setWorkloadPostponeRatio(Convert.toBigDecimal(1).subtract(performanceVoV2.getInTimeWorkloadRatio()));

				List<MaintainSign> maintainSigns = signMap.get(userId);
				if (maintainSigns != null) {
					performanceVoV2.setSignCounts(Convert.toInt(maintainSigns.size(), 0));
					performanceVoV2.setSignOutCounts(maintainSigns.stream().filter(o -> o.getSignOutTime() != null).collect(Collectors.toList()).size());
					long sum = 0L;
					int counts = 0;
					Map<Long, List<ExcelPlanContentVo>> map = excelPlanContentVos.stream().collect(Collectors.groupingBy(ExcelPlanContentVo::getPlanId));
					for (MaintainSign maintainSign : maintainSigns) {
						ExcelPlanContentVo excelPlanContentVo = map.get(maintainSign.getPlanId()).get(0);
						if (excelPlanContentVo.getPlanStatus() == TaskStatusEnum.BY_SIGN.getStatus()) {
							sum = sum + maintainSign.getTimeInterval();
							counts = counts + 1;
						}
					}
					if (performanceVoV2.getFinishElevatorCount() > 0 && counts > 0) {
						performanceVoV2.setAvgWorkMinute(Convert.toBigDecimal(sum).divide(Convert.toBigDecimal(counts), 2, BigDecimal.ROUND_HALF_UP));
					}
				}
			}
			List<UserSignDetail> userSignDetails = userSignDetailMap.get(userId);
			if (userSignDetails != null) {
				List<UserSignDetail> workList = userSignDetails.stream().filter(o -> o.getHoliday() == 0).collect(Collectors.toList());
				performanceVoV2.setSignDetailCounts(Convert.toInt(workList.size() * 2, 0));
				List<UserSignDetail> normalList1 = workList.stream().filter(o -> o.getSignBeLate() != null && o.getSignBeLate() == 1 && o.getSignType() != null && o.getSignType() == 1).collect(Collectors.toList());
				List<UserSignDetail> normalList2 = workList.stream().filter(o -> o.getSignOutLeaveEarly() != null && o.getSignOutLeaveEarly() != null && o.getSignOutLeaveEarly() == 1 && o.getSignOutType() != null && o.getSignOutType() == 1).collect(Collectors.toList());
				performanceVoV2.setNormalSignDetailCounts(Convert.toInt(normalList1.size() + normalList2.size(), 0));

				List<UserSignDetail> signOutLeaveEarlyList = userSignDetails.stream().filter(o -> o.getSignOutLeaveEarly() != null && o.getSignOutLeaveEarly() == 0).collect(Collectors.toList());
				performanceVoV2.setSignOutLeaveEarlyCount(Convert.toInt(signOutLeaveEarlyList.size(), 0));

				List<UserSignDetail> signAbnormalList1 = userSignDetails.stream().filter(o -> o.getSignType() != null && o.getSignType() == 2).collect(Collectors.toList());
				List<UserSignDetail> signAbnormalList2 = userSignDetails.stream().filter(o -> o.getSignOutType() != null && o.getSignOutType() == 2).collect(Collectors.toList());
				performanceVoV2.setSignAbnormalCount(Convert.toInt(signAbnormalList1.size() + signAbnormalList2.size(), 0));

				List<UserSignDetail> newSignList = userSignDetails.stream().filter(o -> o.getNewSignTime() != null).collect(Collectors.toList());

				List<UserSignDetail> newSignOutList = userSignDetails.stream().filter(o -> o.getNewSignOutTime() != null).collect(Collectors.toList());

				//迟到打卡次数
				List<UserSignDetail> signBeLate = userSignDetails.stream().filter(o -> o.getHoliday() == 0&&Convert.toInt(o.getSignBeLate(),-1) == 0).collect(Collectors.toList());
				performanceVoV2.setBeLateCount(Convert.toInt(signBeLate.size(),0));

				performanceVoV2.setUpdateSignCount(Convert.toInt(newSignList.size(), 0) + Convert.toInt(newSignOutList.size(), 0));
				List<UserSignDetail> disSignList = userSignDetails.stream().filter(o -> o.getSignTime() == null && o.getHoliday() == 0).collect(Collectors.toList());
				List<UserSignDetail> disSignOutList = userSignDetails.stream().filter(o -> o.getSignOutTime() == null && o.getHoliday() == 0).collect(Collectors.toList());
				performanceVoV2.setDisSignCount(Convert.toInt(disSignList.size(), 0) + Convert.toInt(disSignOutList.size(), 0));

				List<UserSignDetail> overtimeList = userSignDetails.stream().filter(o -> o.getHoliday() == 1 && o.getSignTime() != null && o.getSignOutTime() != null).collect(Collectors.toList());
				performanceVoV2.setOvertimeCount(Convert.toInt(overtimeList.size(), 0));
				Integer overtime = performanceVoV2.getOvertime();
				for (UserSignDetail userSignDetail : overtimeList) {
					Date signDate = new Date(userSignDetail.getSignTime());
					Date signOutDate = new Date(userSignDetail.getSignOutTime());
					overtime = overtime + Convert.toInt(DateUtil.between(signDate, signOutDate, DateUnit.MINUTE), 0);
				}
				performanceVoV2.setOvertime(overtime);
			}
			resultList.add(performanceVoV2);
		}
		return resultList;
	}

}
